package monkeyXML;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class XMLTree
{
   private ArrayList<XMLTree> theChildren;
   private ListIterator<XMLTree> theChildIterator;

   // the value of this tree's root tag, or if it isn't a tag at all
   // this will store the value that would exist between two tags.
   private XMLNode theNode = null;

   private boolean isClosingTag = false;
   private boolean isText = false;

   XMLTree( Reader aReader ) throws IOException
   {
      // System.out.println( "Started" );
      boolean emptyElement = false;
      boolean inQuotes = false;

      StringBuffer value = new StringBuffer();

      char current = (char) aReader.read();

      // read off whitespace
      while( current == '\n' || current == ' ' || current == '\r' )
      {
         current = (char) aReader.read();
      }

      if( current == '<' )
      {
         while( current != '>' || inQuotes == true )
         {
            value.append( current );
            current = (char) aReader.read();
            if( current == '"' )
            {
               inQuotes = !inQuotes;
            }
            if( current == '/' && inQuotes == false )
            {
               if( value.toString().compareTo( "<" ) == 0 )
               {
                  isClosingTag = true;
               } else
               {
                  emptyElement = true;
               }
            }
         }
         value.append( current );
         // if( !isClosingTag )

         theNode = new XMLTag( value.toString() );
         // System.out.println( "made: " + theNode.toString() );

         // System.out.println( theNode.toString() + " " + isClosingTag);
         if( !emptyElement && !isClosingTag )
         {
            theChildren = new ArrayList<XMLTree>();
            XMLTree child = new XMLTree( aReader );
            if( child.isText == true )
            {
               theChildren.add( child );
            }
            while( !child.isClosingTag && aReader.ready() )
            {
               // System.out.println( "Try adding new child" );
               theChildren.add( child );
               child = new XMLTree( aReader );
               // System.out.println( "done" );
            }
            theChildIterator = theChildren.listIterator();
         }

      } else
      {
         isText = true;
         isClosingTag = true;
         while( current != '<' || inQuotes == true )
         {
            value.append( current );
            current = (char) aReader.read();
            if( current == '"' )
            {
               inQuotes = !inQuotes;
            }
            if( current == '/' && inQuotes == false )
            {
               emptyElement = true;
            }
         }
         while( current != '>' )
         {
            current = (char) aReader.read();
         }

         theNode = new XMLText( value.toString() );
         // System.out.println( value + " " + isClosingTag);
      }
   }

   public String getTag()
   {
      if( this.isText == true )
      {
         return theNode.toString();
      } else
      {
         return ((XMLTag) theNode).getTag();
      }
   }

   public XMLNode getNode()
   {
      return theNode;
   }

   public String getAttribute( String anAttrib )
   {

      return anAttrib;
   }

   public XMLTree getNextChild()
   {
      return theChildIterator.next();
   }

   public int countChildren()
   {
      int results = 0;
      if( theChildren != null )
      {
         results = theChildren.size();
      }
      return results;
   }

   public void writeToStream( OutputStream aStream ) throws Exception
   {
      aStream.write( '<' );
      aStream.write( theNode.toString().getBytes() );
            
      if( theChildren != null )
      {
         aStream.write( '>' );
         aStream.write( '\n'); //used only to debug
         
         Iterator<XMLTree> i = theChildren.iterator();
         XMLTree t = null;
         do
         {
            t = i.next();
            t.writeToStream( aStream );
         } while( i.hasNext() );
         aStream.write( '<' );
         aStream.write( '/' );
         aStream.write( theNode.getTag().getBytes() );
      }
      else
      {
         aStream.write( '/' );
      }
      aStream.write( '>' );
      aStream.write( '\n'); //used only to debug
   }
}
